package com.asa.tongji;

import java.awt.List;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;

import com.asa.HanShu;
import com.asa.tongji.bean.XiangXianTu;
import com.asa.tongji.bean.ZhiFangTu;
import com.asa.utils.Calculate;
/**
 * 基础的统计分析功能（包含了）
 * @author Administrator
 *
 */
public class TUtils1 {
	/**
	 * 平均值
	 * 
	 * @param x
	 *            计算的数据的组
	 * @return 平均值
	 */
	public static double average(double[] x) {
		double sum = 0;
		for (int i = 0; i < x.length; i++) {
			sum += x[i];
		}
		return sum /(double) (x.length);
	}
	
	/**
	 * 根据离散概率求平均值
	 * 
	 * @param g
	 * @param a
	 * @return
	 */
	public static double average2(double[] g, double[] a) {
		double average = 0;
		for (int i = 0; i < g.length; i++) {
			average += g[i] * a[i];
		}
		return average/(double) (g.length);
	}

	/**
	 * 计算方差 求房产还有一种方法： 方差=平方的期望-期望的平方
	 * 
	 * @param x
	 *            计算的数据的组
	 * @return 方差
	 */
	public static double variance(double[] x) {

		double xa = average(x);
		double sum = 0;
		for (int i = 0; i < x.length; i++) {
			sum += (x[i] - xa) * (x[i] - xa);
		}
		return sum / (x.length);
	}
	public static double variancechafen(double[] x) {

		double xa = average(x);
		double sum = 0;
		for (int i = 0; i < x.length; i++) {
			sum += (x[i] - xa) * (x[i] - xa);
		}
		return sum / (x.length-1);
	}
	
	/**
	 * 在主成分分析中，标准差的分母一般用总数-1
	 * @param x
	 * @return
	 */
	public static double variancezhuchengfenfenxi(double[] x) {

		double xa = average(x);
		double sum = 0;
		for (int i = 0; i < x.length; i++) {
			sum += (x[i] - xa) * (x[i] - xa);
		}
		return sum / (x.length);
	}
	
	/**
	 * 通过 方差=平方的期望-期望的平方 求解方差
	 * 
	 * @param hanShu
	 *            求解函数封装
	 * @param a
	 *            起始点
	 * @param b
	 *            结束点
	 * @return
	 */
	public static double variance2(final HanShu hanShu, double a, double b) {

		double exex = Math.pow(Calculate.hanshujifen(a, b, hanShu), 2);

		HanShu hanShu2 = new HanShu() {

			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return 0;
			}

			@Override
			public double hanshu(double x0) {
				// TODO Auto-generated method stub
				return hanShu.hanshu(x0 * x0);
			}
		};
		double exx = Calculate.hanshujifen(a, b, hanShu2);
		return exx - exex;
	}

	/**
	 * 通过 离散型概率密度 求解方差
	 * 
	 * @param hanShu
	 *            求解函数封装
	 * @param a
	 *            起始点
	 * @param b
	 *            结束点
	 * @return
	 */
	public static double variance3(double[] g, double[] a) {

		double average1 = average2(g, a);

		//System.out.println(average1);
		double[] ave = new double[g.length];
		double average2 = 0;
		for (int i = 0; i < ave.length; i++) {
			ave[i] = a[i] * a[i];
		}
		average2 = average2(g, ave);
		NumberFormat nf = NumberFormat.getInstance();
		nf.setRoundingMode(RoundingMode.HALF_UP);// 设置四舍五入
		nf.setMinimumFractionDigits(6);// 设置最小保留几位小数

		return Double.parseDouble(nf.format(average2 - (average1 * average1)));
	}

	/**
	 * 求解标准差
	 * 
	 * @param x
	 *            计算的数据的组
	 * @return 标准差
	 */
	public static double standardDeviation(double[] x) {
		return Math.sqrt(variance(x));
	}
	public static double standardDeviation_chafen(double[] x) {
		return Math.sqrt(variancechafen(x));
	}
	
	/**
	 * 求解标准差
	 * 
	 * @param x
	 *            计算的数据的组
	 * @return 标准差
	 */
	public static double standardDeviation2(final HanShu hanShu, double a,
			double b) {
		return Math.sqrt(variance2(hanShu, a, b));
	}

	/**
	 * 协方差 这里需要期望，一般如果只有元数据，可用以下方法，直接用平均值代替期望值
	 * 协方差研究的是两者之间有没有关系的方法，完全没有关系时协方差的值为0 数学写法Cov(X,Y) = E(XY)-E(X)E(Y)
	 * 
	 * @param x
	 *            样本空间
	 * @param y
	 *            样本空间
	 * @return 协方差的值
	 * @throws Exception
	 */
	public static double covariance(double[] x, double[] y) throws Exception {
		if (x.length != y.length) {
			throw new Exception();
		}
		double[] xy = new double[y.length];
		for (int i = 0; i < y.length; i++) {
			xy[i] = x[i] * y[i];
		}
		double average = average(xy);

		return average - (average(x) * average(y));
	}

	/**
	 * 相关系数
	 * 性质
	 * 1。 相关系数的范围是-1到1
	 * 2。 如果某个变量的所有值都转化为一个不同的度量单位，r值不变。
	 * 3. r值不受x、 y的选择影响。交换所有的x值与y值，r不变
	 * 4. r是线性相关性的强度的度量，不适用于非线性相关的关系
	 * 5. r非常容易受到离群值的影响，当有离群值存在的时候，r可能变得非常不一样
	 * @param x
	 *            样本空间
	 * @param y
	 *            样本空间
	 * @return 返回相关系数值
	 * @throws Exception
	 */
	public static double correlationCoefficient(double[] x, double[] y)
			throws Exception {
		return covariance(x, y) / (standardDeviation(x) * standardDeviation(y));
	}

	/**
	 * 协方差 通过概率密度函数求方程的协方差
	 * 
	 * @param hanShux
	 *            函数概率密度1
	 * @param hanShuy
	 *            函数概率密度2
	 * @param a
	 *            函数的左区间范围
	 * @param b
	 *            函数的右区间范围
	 *            有很多的概率密度函数他的x范围是正负无穷大，这个计算机无法表示无穷大，只能说是尽量给个很大的范围拟合，反正这种函数都是收敛的
	 * @return 协方差的值
	 * @throws Exception
	 */
	public static double covariance2(final HanShu hanShux,
			final HanShu hanShuy, double a, double b) throws Exception {

		HanShu hanShu = new HanShu() {

			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return 0;
			}

			@Override
			public double hanshu(double x0) {
				// TODO Auto-generated method stub
				return hanShux.hanshu(x0) * hanShuy.hanshu(x0);
			}
		};

		return Calculate.hanshujifen(a, b, hanShu)
				- Calculate.hanshujifen(a, b, hanShux)
				* Calculate.hanshujifen(a, b, hanShuy);
	}

	/**
	 * 相关系数
	 * 
	 * @param hanShux
	 *            函数概率密度1
	 * @param hanShuy
	 *            函数概率密度2
	 * @param a
	 *            函数的左区间范围
	 * @param b
	 *            函数的右区间范围
	 *            有很多的概率密度函数他的x范围是正负无穷大，这个计算机无法表示无穷大，只能说是尽量给个很大的范围拟合，反正这种函数都是收敛的
	 * @return 返回相关系数值
	 * @throws Exception
	 */
	public static double correlationCoefficient2(final HanShu hanShux,
			final HanShu hanShuy, double a, double b) throws Exception {
		return covariance2(hanShux, hanShuy, a, b)
				/ (standardDeviation2(hanShux, a, b) * standardDeviation2(
						hanShuy, a, b));
	}

	/**
	 * 中心极限定理 独立同分部的中心极限定理
	 * 
	 * @param x
	 *            随机变量
	 * @param u
	 *            期望
	 * @param o
	 *            标准差 这个的结果会近似的贴近N(0,1) 这个是数理统计中大样本统计推断的基础，这个可以很好的说明下个方法的正确性
	 * @return
	 */
	public static double standardizedVariable(double[] x, double u, double o) {
		double sum = 0;
		for (int i = 0; i < x.length; i++) {
			sum += x[i];
		}
		return (sum - (x.length + 1) * u) / (Math.sqrt(x.length + 1) * o);
	}

	/**
	 * 中心极限定理 独立同分部的中心极限定理，记住，一旦进入到这个函数，就再也与原来的概率什么的无缘了
	 * 
	 * @param v
	 *            将要计算的可能性数
	 * @param x
	 *            样本均值
	 * @param no
	 *            方差与样本总数的乘积
	 * @return 从负无穷到你想要的p值得概率密度行数概率
	 * 
	 * (X1-u)/(o/sqrt(n))
	 * 
	 * 总的来说就是：（实际均值-申明均值）除以（方差*样本数）的开方
	 * 
	 */

	public static double gailvdegailv(double v, double x, double no) {
		double p = (v - x) / (Math.sqrt(no));
		// 封装的标准正态函数
		HanShu hanShu = new HanShu() {
			@Override
			public double hanshu(double t, double x) {
				// TODO Auto-generated method stub
				return 0;
			}

			@Override
			public double hanshu(double x0) {
				// TODO Auto-generated method stub
				return BaseFunction.normaldistribution(x0, 0, 1);
			}
		};
		double hanshujifen1 = Calculate.hanshujifen(-10, p, hanShu);
		return hanshujifen1;
	}
	
	
	public static void beyesi(){
		double pa = (double)3/7;
		double pb = (double)2/(20*36);
		double pab = 0.9;
		/**
		 * pba = (pab*pb)/pa
		 */
		double pba = (pab*pb)/pa;	
		//System.out.println(pba);
	}
	
	
	
	
	
	
	
	
	

	/**
	 * 直方图所需要求得的参数
	 * 
	 * @param a
	 *            数据样本数组
	 * @param n
	 *            将直方图分成多少分 未测
	 */
	public static ZhiFangTu zhifangtu(double[] a, int n) {
		for (int i = 0; i < a.length; ++i) {
			for (int j = 0; j < a.length - i - 1; ++j) {
				if (a[j] > a[j + 1]) {
					double tmp = a[j];
					a[j] = a[j + 1];
					a[j + 1] = tmp;
				}
			}
		}
		
		
		
		double range = a[a.length - 1] - a[0];
		double length = range / n;
		double[] pinshu = new double[n];
		int j = 0;
		double buffer = a[0] + length;
		for (int i = 0; i < a.length; i++) {
			while (true) {
				if (a[i] <= buffer&&j<n) {
					//System.out.println(j);
					pinshu[j] += 1;
					break;
				} else {
					j++;
					buffer += length;
				}
			}
		}
		double[] pinlv = new double[n];
		//System.out.println(pinshu[0]+"  "+a.length);
		for (int i = 0; i < pinshu.length; i++) {
			pinlv[i] = (double) pinshu[i] / (double) (a.length);
		}

		ZhiFangTu tu = new ZhiFangTu();
		tu.setBuchang(length);
		tu.setPinshu(pinshu);
		tu.setPinlv(pinlv);
		tu.setA(a);
		return tu;
	}

	/**
	 * 箱线图需要的一些参数
	 * 
	 * @param a
	 *            数据样本数组
	 * @return 封装的箱线图参数
	 */

	public static XiangXianTu xiangxiantu(double[] a) {
		XiangXianTu tu = new XiangXianTu();
		for (int i = 0; i < a.length; ++i) {
			for (int j = 0; j < a.length - i - 1; ++j) {
				if (a[j] > a[j + 1]) {
					double tmp = a[j];
					a[j] = a[j + 1];
					a[j + 1] = tmp;
				}
			}
		}
		tu.setA(a);
		int np1 = (int) (a.length * 0.25);
		int np2 = (int) (a.length * 0.5);
		int np3 = (int) (a.length * 0.75);
		double q1, q2, q3;
		if (np1 % 2 != 1) {
			q1 = (a[np1] + a[np1 - 1]) / 2;
		} else {
			q1 = a[np1];
		}
		if (np2 % 2 != 1) {
			q2 = (a[np2] + a[np2 - 1]) / 2;
		} else {
			q2 = a[np2];
		}
		if (np3 % 2 != 1) {
			q3 = (a[np3] + a[np3 - 1]) / 2;
		} else {
			q3 = a[np3];
		}
		HashMap<Integer, Double> map = new HashMap<Integer, Double>();
		map.put(np1, q1);
		map.put(np2, q2);
		map.put(np3, q3);
		tu.setN(map);
		
		ArrayList<Double> yichangdian = new ArrayList<Double>();
		double iqr = q3-q1;//四分位距
		double iqr1 = q1 - iqr*1.5;
		double iqr3 = q2 + iqr*1.5;
		for (int i = 0; i < a.length; i++) {
			if (a[i]<iqr1||a[i]>iqr3) {
				yichangdian.add(a[i]);
			}
		}
		double[] bianyuan = new double[2]; 
		for (int i = 0; i < a.length; i++) {
			if (!yichangdian.contains(a[i])) {
				bianyuan[0] = a[i];
				break;
			}
		}
		for (int i = a.length-1; i >= 0; i--) {
			if (!yichangdian.contains(a[i])) {
				bianyuan[1] = a[i];
				break;
			}
		}
		tu.setYichangdian(yichangdian);
		tu.setShangxiabianyuan(bianyuan);
		return tu;
	}

	/**
	 * 样本k阶（原点）矩
	 * 
	 * @param x
	 *            样本组
	 * @param k
	 *            k阶
	 * @return k阶矩结果
	 */
	public static double kjieyuandianju(double[] x, int k) {
		double all = 0;
		for (int i = 0; i < x.length; i++) {
			all += Math.pow(x[i], k);
		}
		return all / (double) x.length;
	}

	/**
	 * k阶中心矩
	 * 
	 * @param x
	 *            样本组
	 * @param k
	 *            k阶
	 * @return k阶中心矩
	 */
	public static double kjiezhongxinju(double[] x, int k) {
		double variance = variance(x);

		double all = 0;
		for (int i = 0; i < x.length; i++) {
			all += Math.pow(x[i] - variance, k);
		}
		return all / (double) x.length;
	}
 
	

	
	public static void main(String[] args) {
//		double[] a = {1,6,3,4,8,2,20};
//		XiangXianTu xiangxiantu = xiangxiantu(a);
//		//System.out.println(xiangxiantu);
		
		
		NumberFormat nf = NumberFormat.getInstance();
		nf.setRoundingMode(RoundingMode.HALF_UP);// 设置四舍五入
		nf.setMinimumFractionDigits(1);// 设置最小保留几位小数
//		nf.format(1.2553324);
		//System.out.println(nf.format(1.2153324));
		
		DecimalFormat df = new DecimalFormat("#.00");
		//System.out.println(df.format(2.1024123));
	}

}
